﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Forms;

using MySpring;
using MyUtils;
using MyUtils.PInvoke;

using SolutionOrchestrator.Validators;

using Wpf.Controls;

using MenuItem = System.Windows.Controls.MenuItem;
using MessageBox = System.Windows.Forms.MessageBox;

namespace SolutionOrchestrator
{
	public partial class MainWindow
	{
		readonly ISpringContainer _services = SpringContainer.Root;
		readonly DataCtx _ctx;

		public MainWindow()
		{
			_services.Add<DataCtx>();
			_services.Add(Dispatcher);

			InitializeComponent();
			DataContext = _ctx = _services.Get<DataCtx>();
		}

		private void ButtonBrowseClick(object sender, RoutedEventArgs e)
		{
			var settings = _services.Get<IMySettingsProvider>();
			var res = OpenFolderDialog(settings.CurrentRootPath);
			if (res != null)
			{
				if (!settings.RootPathCollection.Contains(res))
				{
					settings.RootPathCollection.Add(res);
				}
				settings.CurrentRootPath = res;
			}
		}

		string OpenFolderDialog(string sugg = null)
		{
			var fbd = new MyFolderBrowserDialog { SelectedPath = sugg ?? "" };
			//var fbd = new FolderBrowserDialog { SelectedPath = sugg ?? "" };
			if (fbd.ShowDialog() == System.Windows.Forms.DialogResult.OK)
			{
				return fbd.SelectedPath;
			}
			return null;
		}

		private void ComboBoxSelectionChanged(object sender, SelectionChangedEventArgs e)
		{
			BadReferences.FixableBadReference.ClearCaches();
			PathHelper.CacheReset();
			_services.Get<IAnalyzer>().RecreateWatcher();
			_services.Get<IAnalyzer>().ScheduleRescan(true);
		}

		private void ButtonRefreshClick(object sender, RoutedEventArgs e)
		{
			BadReferences.FixableBadReference.ClearCaches();
			PathHelper.CacheReset();
			_services.Get<IAnalyzer>().ScheduleRescan(true);
		}

		private void SplitButton_Loaded(object sender, RoutedEventArgs e)
		{
			// InitFuckingDummySplitButton(sender);
		}

		void InitFuckingDummySplitButton(object sender)
		{
			var btn = sender as SplitButton;
			var violation = btn.DataContext as FixableViolation;
			InitMenuItems(btn, violation);
		}

		void InitMenuItems(SplitButton btn, FixableViolation violation)
		{
			if (violation != null)
			{
				if (btn.Items.Count == 0)
				{
					Fill(btn, violation);
				}
				violation.PropertyChanged += (s, e) =>
				{
					btn.Items.Clear();
					Fill(btn, violation);
				};
			}
		}

		static void Fill(SplitButton btn, FixableViolation violation)
		{
			var usual = violation.FixesAvailable.TakeWhile(x => x != null).ToArray();
			foreach (var fix in usual)
			{
				FillItem(btn, violation, fix);
			}
			var rest = violation.FixesAvailable.Skip(usual.Length).Where(x => x != null).ToArray();

			FillLevel(0, btn.Items, violation, rest);
		}

		class FixPathLevelComparer : IEqualityComparer<Fix>
		{
			readonly int _level;

			public FixPathLevelComparer(int level)
			{
				_level = level;
			}

			public bool Equals(Fix x, Fix y)
			{
				return string.Equals(Key(x), Key(y), StringComparison.InvariantCultureIgnoreCase);
			}

			public string Key(Fix fix)
			{
				return Key(PathSplitted(fix));
			}

			string Key(PathSplitted path)
			{
				return path.Parts.Length > _level ? path.Parts[_level] : null;
			}

			public PathSplitted PathSplitted(Fix fix)
			{
				return new PathSplitted(fix.ToString());
			}

			public int GetHashCode(Fix fix)
			{
				var key = Key(fix);
				return key == null ? 0 : key.GetHashCode();
			}

			static readonly Dictionary<int, FixPathLevelComparer> _cache = new Dictionary<int, FixPathLevelComparer>();

			public static FixPathLevelComparer Level(int level)
			{
				FixPathLevelComparer result;
				if (!_cache.TryGetValue(level, out result))
				{
					_cache[level] = result = new FixPathLevelComparer(level);
				}
				return result;
			}
		}

		static void FillLevel(int level,ItemCollection col, FixableViolation violation, IEnumerable<Fix> arr)
		{
			var comparer = FixPathLevelComparer.Level(level);
			var groups = arr.GroupBy(x => x, comparer);
			foreach (var group in groups)
			{
				var label = comparer.Key(group.Key);
				var path = comparer.PathSplitted(group.Key);
				if (label != null)
				{
					FillLevel(level + 1, FillItem(col, violation, path.Parts.Length - 1 == level ? group.Key : null, label).Items, violation, group);
				}
			}
		}

		class PathSplitted
		{
			public PathSplitted(string path)
			{
				Parts = path.Split(new[] { Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar }, StringSplitOptions.RemoveEmptyEntries);
			}

			public readonly string[] Parts;
		}

		static void FillItem(SplitButton btn, FixableViolation violation, Fix fix)
		{
			FillItem(btn.Items, violation, fix);
		}

		static MenuItem FillItem(ItemCollection col, FixableViolation violation, Fix fix = null, string label = null)
		{
			if (label == null && fix == null)
			{
				throw new ArgumentNullException("",@"label and path");
			}
			if (label == null)
			{
				label = fix.ToString();
			}

			var mi = new MenuItem { Header = label, Tag = fix, IsChecked = fix != null && fix.Recommended };
			col.Add(mi);
			if (fix != null)
			{
				mi.Click += (s, e) =>
				{
					var mi2 = (MenuItem)s;
					var fix2 = (Fix)mi2.Tag;
					violation.ApplyFix(fix2);
				};
			}
			return mi;
		}

		private void SplitButton_DataContextChanged(object sender, DependencyPropertyChangedEventArgs e)
		{
			InitFuckingDummySplitButton(sender);
		}

		private void SplitButton_Click(object sender, RoutedEventArgs e)
		{
			var sb = (SplitButton)sender;

			if (sb.Attached().IsMenuLoaded != true)
			{
				sb.Attached().IsMenuLoaded = true;
				InitFuckingDummySplitButton(sender);
			}

			var violation = (FixableViolation)sb.DataContext;
			if (!violation.DefaultExists)
			{
				sb.IsContextMenuOpen = true;
			}
		}

		private void Button_SourceControlAccept_Click(object sender, RoutedEventArgs e)
		{
			_ctx.Settings.SourceControl.AcceptedByUser = true;
			Button_SourceControlHide_Click(null, null);
		}

		void Button_SourceControlHide_Click(object sender, RoutedEventArgs e)
		{
			_ctx.ShowSourceControlSettings = false;
		}
	}
}
